#pragma once

#include <stdint.h>

#include "luster_flow.hh"
#include "luster_status.hh"

namespace luster {

template <typename T> struct IDrop {
	static void drop(T *data__) {
		luster_UNUSED(data);
	}
};

template <typename T> void drop(T *data) {
	IDrop<T>::drop(data);
}

template <typename T> void drop_range(T *start, UInt len) {
	for_range(0, len) {
		drop(start + it);
	}
}

#define luster_DROP(M_T, M_ptr) \
	template <> struct IDrop<M_T> { \
		static void drop(M_T *M_ptr); \
	}; \
	inline void IDrop<M_T>::drop(M_T *M_ptr)

#define luster_DROP_FOR(M_T, M_C, M_ptr) \
	template <typename M_T> struct IDrop<M_C> { \
		static void drop(M_C *M_ptr); \
	}; \
	template <typename M_T> void IDrop<M_C>::drop(M_C *M_ptr)

template <typename T> struct Owned {
	~Owned() {
		if (inner == nullptr)
			return;
		drop(inner);
		inner = nullptr;
	}

	T *inner{};
};

template <typename T> Owned<T> MarkOwn(T *data) {
	Owned<T> own;
	own.inner = data;
	return own;
}

#define luster_CONCAT(M_x, M_y) M_x##M_y

#define luster_OWN__aux(M_x, M_line) \
	auto luster_CONCAT(own__, M_line) = ::luster::MarkOwn(&(M_x))

#define luster_OWN(M_x) luster_OWN__aux(M_x, __LINE__)

} // namespace luster
